#include "OCREngine.h"
#include "Auxiliary.h"

#include <cv.h>
#include <highgui.h>
#include <iostream>
using std::cout;
using std::endl;
#include <string>
using std::string;
#include <fstream>
using std::ifstream;

OCREngine::OCREngine(void)
:m_init(false)
{
}

OCREngine::~OCREngine(void)
{
	for (t_imglist::iterator it = m_db.begin() ; it != m_db.end() ; ++it)
		cvReleaseImage(&(*it).first);
}

bool OCREngine::init (const std::string &digitdir) {
	assert(!m_init);
	assert(digitdir.at(digitdir.size() - 1) == '/'); // assert the dir we got ends with a '/'

	// important note:
	// all images must be exactly same size!
	ifstream index;
	index.open((digitdir + "index").c_str());
	assert(index); // else no database
	string img_file, img_meaning;
	while (getline(index, img_file, ':') && getline(index, img_meaning))
		m_db.push_back(t_imgmember(cvLoadImage((digitdir + img_file).c_str(), IPL_DEPTH_8U), Auxiliary::fromString<int>(img_meaning)));
	index.close();
	return m_init = true;
}

int OCREngine::identify (const IplImage* digit) const {
	assert(m_init);
	assert(m_db.size() > 0 && m_db.front().first);

	IplImage* resized(cvCreateImage(cvSize(m_db.front().first->width, m_db.front().first->height), IPL_DEPTH_8U , 1));
	cvResize(digit, resized);
	
	unsigned long minerr(ULONG_MAX);
	int bestmatch(-1);

	for (t_imglist::const_iterator it = m_db.begin() ; it != m_db.end() ; ++it) {
		unsigned long err(computeSquareError(resized, (*it).first));
		if (err < minerr) {
			bestmatch = (*it).second;
			minerr = err;
		}
	}

	cvReleaseImage(&resized);

	return bestmatch;
}

unsigned long OCREngine::computeSquareError (IplImage* one, IplImage* two) const {
	assert(one->width == two->width && one->height == two->height);
	unsigned long res(0);
	for(int i(0) ; i < one->height ; ++i) {
		for(int j(0) ; j < one->width ; ++j) {
			uchar &pxl1(CV_IMAGE_ELEM(one, uchar, i, j));
			uchar &pxl2(CV_IMAGE_ELEM(two, uchar, i, j));
			
			res += (pxl1-pxl2) * (pxl1-pxl2);
		}
	}

	return res;
}
